package designpattern

type Iterator[V any] interface {
	HasNext() bool
	Next() V
}

type ArrayList[V any] struct {
	data []V
}

func NewArrayList[V any](v ...V) ArrayList[V] {
	return ArrayList[V]{data: v}
}

func (array *ArrayList[V]) Iterator() *ArrayListIterator[V] {
	return &ArrayListIterator[V]{currIndex: 0, list: array}
}

type ArrayListIterator[V any] struct {
	currIndex int
	list      *ArrayList[V]
}

func (iterator *ArrayListIterator[V]) HasNext() bool {
	return len(iterator.list.data) > iterator.currIndex
}

func (iterator *ArrayListIterator[V]) Next() V {
	if len(iterator.list.data) > iterator.currIndex {
		v := iterator.list.data[iterator.currIndex]
		iterator.currIndex++
		return v
	} else {
		var v V
		return v
	}

}

type HashSet[V comparable] struct {
	data map[V]bool
}

func NewHashSet[V comparable](v ...V) HashSet[V] {
	mapPool := make(map[V]bool)
	for _, element := range v {
		if _, ok := mapPool[element]; !ok {
			mapPool[element] = true
		}
	}
	return HashSet[V]{data: mapPool}
}

func (hashSet *HashSet[V]) Iterator() *HashSetIterator[V] {
	keys := make([]V, 0, len(hashSet.data))
	for k := range hashSet.data {
		keys = append(keys, k)
	}
	return &HashSetIterator[V]{currIndex: 0, set: keys}
}

type HashSetIterator[V any] struct {
	currIndex int
	set       []V
}

func (iterator *HashSetIterator[V]) HasNext() bool {
	return len(iterator.set) > iterator.currIndex
}

func (iterator *HashSetIterator[V]) Next() V {
	if len(iterator.set) > iterator.currIndex {
		v := iterator.set[iterator.currIndex]
		iterator.currIndex++
		return v
	} else {
		var v V
		return v
	}

}
